using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Runtime.InteropServices;
using System.Runtime.Serialization;
using System.Security;
using System.Threading;

namespace Net.System
{
    /// <summary>
    /// 无GC快速字典
    /// </summary>
    /// <typeparam name="TKey"></typeparam>
    /// <typeparam name="TValue"></typeparam>
    [DebuggerTypeProxy(typeof(Mscorlib_DictionaryDebugView<,>))]
    [DebuggerDisplay("Count = {Count}")]
    [ComVisible(false)]
    public class MyDictionary<TKey, TValue> : IDictionary<TKey, TValue>, ICollection<KeyValuePair<TKey, TValue>>, IEnumerable<KeyValuePair<TKey, TValue>>, IEnumerable, IDictionary, ICollection, IReadOnlyDictionary<TKey, TValue>, IReadOnlyCollection<KeyValuePair<TKey, TValue>>, ISerializable, IDeserializationCallback
    {
        internal int[] buckets;
        public Entry[] entries; //unity的editor用到
        public int count;
        private int freeList;
        private int freeCount;
        private IEqualityComparer<TKey> comparer;
        private KeyCollection keys;
        private ValueCollection values;
        private object _syncRoot = new ();

        public MyDictionary() : this(1, null)
        {
        }

        public MyDictionary(int capacity) : this(capacity, null)
        {
        }

        public MyDictionary(IEqualityComparer<TKey> comparer) : this(1, comparer)
        {
        }

        public MyDictionary(int capacity, IEqualityComparer<TKey> comparer)
        {
            if (capacity < 0)
                ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.capacity);
            if (capacity > 0)
                Initialize(capacity);
            this.comparer = comparer ?? EqualityComparer2<TKey>.CreateDefaultEqualityComparer();
        }

        public MyDictionary(IDictionary<TKey, TValue> dictionary) : this(dictionary, null)
        {
        }

        public MyDictionary(IDictionary<TKey, TValue> dictionary, IEqualityComparer<TKey> comparer) : this((dictionary != null) ? dictionary.Count : 1, comparer)
        {
            if (dictionary == null)
                ThrowHelper.ThrowArgumentNullException(ExceptionArgument.dictionary);
            foreach (KeyValuePair<TKey, TValue> keyValuePair in dictionary)
                Add(keyValuePair.Key, keyValuePair.Value);
        }

        protected MyDictionary(SerializationInfo info, StreamingContext context)
        {
            HashHelpers.SerializationInfoTable.Add(this, info);
        }

        public IEqualityComparer<TKey> Comparer => comparer;

        public int Count => count - freeCount;

        public KeyCollection Keys => keys ??= new KeyCollection(this);

        ICollection<TKey> IDictionary<TKey, TValue>.Keys => Keys;

        IEnumerable<TKey> IReadOnlyDictionary<TKey, TValue>.Keys => Keys;

        public ValueCollection Values => values ??= new ValueCollection(this);

        ICollection<TValue> IDictionary<TKey, TValue>.Values => Values;

        IEnumerable<TValue> IReadOnlyDictionary<TKey, TValue>.Values => Values;

        public TValue this[TKey key]
        {
            get
            {
                int num = FindEntry(key);
                if (num >= 0)
                    return entries[num].value;
                ThrowHelper.ThrowKeyNotFoundException();
                return default;
            }
            set
            {
                Insert(key, value, false, true, out _, out _);
            }
        }

        public void Add(TKey key, TValue value)
        {
            Insert(key, value, true, false, out _, out _);
        }

        public bool TryAdd(TKey key, TValue value)
        {
            return Insert(key, value, false, true, out _, out _);
        }

        public bool TryAdd(TKey key, TValue value, out TValue oldValue)
        {
            return Insert(key, value, false, true, out oldValue, out _);
        }

        public bool TryAdd(TKey key, TValue value, bool replace)
        {
            return Insert(key, value, false, replace, out _, out _);
        }

        public bool TryAdd(TKey key, TValue value, bool replace, out TValue oldValue)
        {
            return Insert(key, value, false, replace, out oldValue, out _);
        }

        void ICollection<KeyValuePair<TKey, TValue>>.Add(KeyValuePair<TKey, TValue> keyValuePair)
        {
            Add(keyValuePair.Key, keyValuePair.Value);
        }

        bool ICollection<KeyValuePair<TKey, TValue>>.Contains(KeyValuePair<TKey, TValue> keyValuePair)
        {
            int num = FindEntry(keyValuePair.Key);
            return num >= 0 && EqualityComparer<TValue>.Default.Equals(entries[num].value, keyValuePair.Value);
        }

        bool ICollection<KeyValuePair<TKey, TValue>>.Remove(KeyValuePair<TKey, TValue> keyValuePair)
        {
            int num = FindEntry(keyValuePair.Key);
            if (num >= 0 && EqualityComparer<TValue>.Default.Equals(entries[num].value, keyValuePair.Value))
            {
                Remove(keyValuePair.Key);
                return true;
            }
            return false;
        }

        public void Clear()
        {
            if (count > 0)
            {
                for (int i = 0; i < buckets.Length; i++)
                    buckets[i] = -1;
                Array.Clear(entries, 0, count);
                freeList = -1;
                count = 0;
                freeCount = 0;
            }
        }

        public bool ContainsKey(TKey key)
        {
            return FindEntry(key) >= 0;
        }

        public bool ContainsValue(TValue value)
        {
            if (value == null)
            {
                for (int i = 0; i < count; i++)
                {
                    if (entries[i].hashCode >= 0 && entries[i].value == null)
                        return true;
                }
            }
            else
            {
                var @default = EqualityComparer<TValue>.Default;
                for (int j = 0; j < count; j++)
                {
                    if (entries[j].hashCode >= 0 && @default.Equals(entries[j].value, value))
                        return true;
                }
            }
            return false;
        }

        private void CopyTo(KeyValuePair<TKey, TValue>[] array, int index)
        {
            if (array == null)
                ThrowHelper.ThrowArgumentNullException(ExceptionArgument.array);
            if (index < 0 || index > array.Length)
                ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.index, ExceptionResource.ArgumentOutOfRange_NeedNonNegNum);
            if (array.Length - index < Count)
                ThrowHelper.ThrowArgumentException(ExceptionResource.Arg_ArrayPlusOffTooSmall);
            int num = count;
            var array2 = entries;
            for (int i = 0; i < num; i++)
            {
                if (array2[i].hashCode >= 0)
                    array[index++] = new KeyValuePair<TKey, TValue>(array2[i].key, array2[i].value);
            }
        }

        public Enumerator GetEnumerator()
        {
            return new Enumerator(this);
        }

        IEnumerator<KeyValuePair<TKey, TValue>> IEnumerable<KeyValuePair<TKey, TValue>>.GetEnumerator()
        {
            return new Enumerator(this);
        }

        [SecurityCritical]
        public virtual void GetObjectData(SerializationInfo info, StreamingContext context)
        {
            if (info == null)
                ThrowHelper.ThrowArgumentNullException(ExceptionArgument.info);
            info.AddValue("Comparer", HashHelpers.GetEqualityComparerForSerialization(comparer), typeof(IEqualityComparer<TKey>));
            info.AddValue("HashSize", (buckets == null) ? 0 : buckets.Length);
            if (buckets != null)
            {
                KeyValuePair<TKey, TValue>[] array = new KeyValuePair<TKey, TValue>[Count];
                CopyTo(array, 0);
                info.AddValue("KeyValuePairs", array, typeof(KeyValuePair<TKey, TValue>[]));
            }
        }

        private int FindEntry(TKey key)
        {
            int num = comparer.GetHashCode(key) & int.MaxValue;
            for (int i = buckets[num % buckets.Length]; i >= 0; i = entries[i].next)
            {
                if (entries[i].hashCode == num)
                {
                    if (!comparer.Equals(entries[i].key, key))
                        continue;
                    return i;
                }
            }
            return -1;
        }

        private void Initialize(int capacity)
        {
            int prime = HashHelpers.GetPrime(capacity);
            buckets = new int[prime];
            for (int i = 0; i < buckets.Length; i++)
                buckets[i] = -1;
            entries = new Entry[prime];
            freeList = -1;
        }

        protected virtual bool Insert(TKey key, TValue value, bool hasKeyThrow, bool replace, out TValue oldValue, out int index)
        {
            int hashCode = key.GetHashCode() & int.MaxValue;
            int hashIndex = hashCode % buckets.Length;
            int depth = 0;
            for (int i = buckets[hashIndex]; i >= 0; i = entries[i].next)
            {
                if (entries[i].hashCode == hashCode)
                {
                    if (!comparer.Equals(key, entries[i].key))
                        continue;
                    if (hasKeyThrow)
                        throw new Exception($"已经有{key}键存在!, 添加失败!");
                    oldValue = entries[i].value;
                    if (replace)
                        entries[i].value = value;
                    index = i;
                    return false;
                }
                depth++;
            }
            if (freeCount > 0)
            {
                index = freeList;
                freeList = entries[index].next;
                freeCount--;
            }
            else
            {
                if (count == entries.Length)
                {
                    Resize();
                    hashIndex = hashCode % buckets.Length;
                }
                index = count;
                count++;
            }
            entries[index].hashCode = hashCode;
            entries[index].next = buckets[hashIndex];
            entries[index].key = key;
            entries[index].value = value;
            buckets[hashIndex] = index;
            if (depth > 100 /*&& HashHelpers.IsWellKnownEqualityComparer(comparer)*/)
            {
                //comparer = (IEqualityComparer<TKey>)HashHelpers.GetRandomizedEqualityComparer(comparer);
                Resize(entries.Length, true);
            }
            oldValue = default;
            return true;
        }

        public virtual void OnDeserialization(object sender)
        {
            SerializationInfo serializationInfo;
            HashHelpers.SerializationInfoTable.TryGetValue(this, out serializationInfo);
            if (serializationInfo == null)
                return;
            int int2 = serializationInfo.GetInt32("HashSize");
            comparer = (IEqualityComparer<TKey>)serializationInfo.GetValue("Comparer", typeof(IEqualityComparer<TKey>));
            if (int2 != 0)
            {
                buckets = new int[int2];
                for (int i = 0; i < buckets.Length; i++)
                    buckets[i] = -1;
                entries = new Entry[int2];
                freeList = -1;
                KeyValuePair<TKey, TValue>[] array = (KeyValuePair<TKey, TValue>[])serializationInfo.GetValue("KeyValuePairs", typeof(KeyValuePair<TKey, TValue>[]));
                if (array == null)
                    ThrowHelper.ThrowSerializationException(ExceptionResource.Serialization_MissingKeys);
                for (int j = 0; j < array.Length; j++)
                {
                    if (array[j].Key == null)
                        ThrowHelper.ThrowSerializationException(ExceptionResource.Serialization_NullKey);
                    Insert(array[j].Key, array[j].Value, true, true, out _, out _);
                }
            }
            else
                buckets = null;
            HashHelpers.SerializationInfoTable.Remove(this);
        }

        private void Resize()
        {
            Resize(HashHelpers.ExpandPrime(count), false);
        }

        private void Resize(int newSize, bool forceNewHashCodes)
        {
            int[] array = new int[newSize];
            for (int i = 0; i < array.Length; i++)
                array[i] = -1;
            var array2 = new Entry[newSize];
            Array.Copy(entries, 0, array2, 0, count);
            if (forceNewHashCodes)
            {
                for (int j = 0; j < count; j++)
                {
                    if (array2[j].hashCode != -1)
                        array2[j].hashCode = array2[j].key.GetHashCode() & int.MaxValue;
                }
            }
            for (int k = 0; k < count; k++)
            {
                if (array2[k].hashCode >= 0)
                {
                    int num = array2[k].hashCode % newSize;
                    array2[k].next = array[num];
                    array[num] = k;
                }
            }
            buckets = array;
            entries = array2;
        }

        public bool Remove(TKey key)
        {
            return TryRemove(key, out _);
        }

        public virtual bool TryRemove(TKey key, out TValue value)
        {
            int num = key.GetHashCode() & int.MaxValue;
            int num2 = num % buckets.Length;
            int num3 = -1;
            for (int i = buckets[num2]; i >= 0; i = entries[i].next)
            {
                if (entries[i].hashCode == num)
                {
                    if (!comparer.Equals(key, entries[i].key))
                        continue;
                    if (num3 < 0)
                        buckets[num2] = entries[i].next;
                    else
                        entries[num3].next = entries[i].next;
                    value = entries[i].value;
                    entries[i].hashCode = -1;
                    entries[i].next = freeList;
                    entries[i].key = default;
                    entries[i].value = default;
                    freeList = i;
                    freeCount++;
                    return true;
                }
                num3 = i;
            }
            value = default;
            return false;
        }

        public bool TryGetValue(TKey key, out TValue value)
        {
            int num = FindEntry(key);
            if (num >= 0)
            {
                value = entries[num].value;
                return true;
            }
            value = default;
            return false;
        }

        public bool TryGetValue(TKey key, out TValue value, out int index)
        {
            index = FindEntry(key);
            if (index >= 0)
            {
                value = entries[index].value;
                return true;
            }
            value = default;
            return false;
        }

        internal TValue GetValueOrDefault(TKey key)
        {
            int num = FindEntry(key);
            if (num >= 0)
                return entries[num].value;
            return default;
        }

        public ref TValue GetValueRefOrAddDefault(TKey key, out bool exists)
        {
            int num = FindEntry(key);
            if (num >= 0)
            {
                exists = true;
                return ref entries[num].value;
            }
            exists = false;
            Insert(key, default, true, true, out _, out num);
            return ref entries[num].value;
        }

        bool ICollection<KeyValuePair<TKey, TValue>>.IsReadOnly => false;

        void ICollection<KeyValuePair<TKey, TValue>>.CopyTo(KeyValuePair<TKey, TValue>[] array, int index)
        {
            CopyTo(array, index);
        }

        void ICollection.CopyTo(Array array, int index)
        {
            if (array == null)
                ThrowHelper.ThrowArgumentNullException(ExceptionArgument.array);
            if (array.Rank != 1)
                ThrowHelper.ThrowArgumentException(ExceptionResource.Arg_RankMultiDimNotSupported);
            if (array.GetLowerBound(0) != 0)
                ThrowHelper.ThrowArgumentException(ExceptionResource.Arg_NonZeroLowerBound);
            if (index < 0 || index > array.Length)
                ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.index, ExceptionResource.ArgumentOutOfRange_NeedNonNegNum);
            if (array.Length - index < Count)
                ThrowHelper.ThrowArgumentException(ExceptionResource.Arg_ArrayPlusOffTooSmall);
            KeyValuePair<TKey, TValue>[] array2 = array as KeyValuePair<TKey, TValue>[];
            if (array2 != null)
            {
                CopyTo(array2, index);
                return;
            }
            if (array is DictionaryEntry[])
            {
                DictionaryEntry[] array3 = array as DictionaryEntry[];
                Entry[] array4 = entries;
                for (int i = 0; i < count; i++)
                {
                    if (array4[i].hashCode >= 0)
                        array3[index++] = new DictionaryEntry(array4[i].key, array4[i].value);
                }
                return;
            }
            object[] array5 = array as object[];
            if (array5 == null)
                ThrowHelper.ThrowArgumentException(ExceptionResource.Argument_InvalidArrayType);
            try
            {
                int num = count;
                Entry[] array6 = entries;
                for (int j = 0; j < num; j++)
                {
                    if (array6[j].hashCode >= 0)
                        array5[index++] = new KeyValuePair<TKey, TValue>(array6[j].key, array6[j].value);
                }
            }
            catch (ArrayTypeMismatchException)
            {
                ThrowHelper.ThrowArgumentException(ExceptionResource.Argument_InvalidArrayType);
            }
        }

        IEnumerator IEnumerable.GetEnumerator()
        {
            return new Enumerator(this);
        }

        bool ICollection.IsSynchronized => false;

        object ICollection.SyncRoot
        {
            get
            {
                return _syncRoot;
            }
        }

        bool IDictionary.IsFixedSize => false;

        bool IDictionary.IsReadOnly => false;

        ICollection IDictionary.Keys => Keys;

        ICollection IDictionary.Values => Values;

        object IDictionary.this[object key]
        {
            get
            {
                if (IsCompatibleKey(key))
                {
                    int num = FindEntry((TKey)key);
                    if (num >= 0)
                        return entries[num].value;
                }
                return null;
            }
            set
            {
                if (key == null)
                    ThrowHelper.ThrowArgumentNullException(ExceptionArgument.key);
                ThrowHelper.IfNullAndNullsAreIllegalThenThrow<TValue>(value, ExceptionArgument.value);
                try
                {
                    TKey key2 = (TKey)key;
                    try
                    {
                        this[key2] = (TValue)value;
                    }
                    catch (InvalidCastException)
                    {
                        ThrowHelper.ThrowWrongValueTypeArgumentException(value, typeof(TValue));
                    }
                }
                catch (InvalidCastException)
                {
                    ThrowHelper.ThrowWrongKeyTypeArgumentException(key, typeof(TKey));
                }
            }
        }

        private static bool IsCompatibleKey(object key)
        {
            if (key == null)
                ThrowHelper.ThrowArgumentNullException(ExceptionArgument.key);
            return key is TKey;
        }

        void IDictionary.Add(object key, object value)
        {
            if (key == null)
                ThrowHelper.ThrowArgumentNullException(ExceptionArgument.key);
            ThrowHelper.IfNullAndNullsAreIllegalThenThrow<TValue>(value, ExceptionArgument.value);
            try
            {
                TKey key2 = (TKey)key;
                try
                {
                    Add(key2, (TValue)value);
                }
                catch (InvalidCastException)
                {
                    ThrowHelper.ThrowWrongValueTypeArgumentException(value, typeof(TValue));
                }
            }
            catch (InvalidCastException)
            {
                ThrowHelper.ThrowWrongKeyTypeArgumentException(key, typeof(TKey));
            }
        }

        bool IDictionary.Contains(object key)
        {
            return IsCompatibleKey(key) && ContainsKey((TKey)key);
        }

        IDictionaryEnumerator IDictionary.GetEnumerator()
        {
            return new Enumerator(this);
        }

        void IDictionary.Remove(object key)
        {
            if (IsCompatibleKey(key))
                Remove((TKey)key);
        }

        public struct Entry
        {
            public int hashCode;
            public int next;
            public TKey key;
            public TValue value;
        }

        [Serializable]
        public struct Enumerator : IEnumerator<KeyValuePair<TKey, TValue>>, IDisposable, IEnumerator, IDictionaryEnumerator
        {
            private readonly MyDictionary<TKey, TValue> dictionary;
            private int index;
            private KeyValuePair<TKey, TValue> current;
            internal const int DictEntry = 1;
            internal const int KeyValuePair = 2;

            internal Enumerator(MyDictionary<TKey, TValue> dictionary)
            {
                this.dictionary = dictionary;
                index = 0;
                current = default;
            }

            public bool MoveNext()
            {
                while (index < dictionary.count)
                {
                    if (dictionary.entries[index].hashCode >= 0)
                    {
                        current = new KeyValuePair<TKey, TValue>(dictionary.entries[index].key, dictionary.entries[index].value);
                        index++;
                        return true;
                    }
                    index++;
                }
                index = dictionary.count + 1;
                current = default;
                return false;
            }

            public KeyValuePair<TKey, TValue> Current => current;

            public void Dispose()
            {
            }

            object IEnumerator.Current => current;

            void IEnumerator.Reset()
            {
                index = 0;
                current = default;
            }

            DictionaryEntry IDictionaryEnumerator.Entry => new DictionaryEntry(current.Key, current.Value);

            object IDictionaryEnumerator.Key => current.Key;

            object IDictionaryEnumerator.Value => current.Value;
        }

        [DebuggerTypeProxy(typeof(Mscorlib_DictionaryKeyCollectionDebugView<,>))]
        [DebuggerDisplay("Count = {Count}")]
        [Serializable]
        public sealed class KeyCollection : ICollection<TKey>, IEnumerable<TKey>, IEnumerable, ICollection, IReadOnlyCollection<TKey>
        {
            private readonly MyDictionary<TKey, TValue> dictionary;

            public KeyCollection(MyDictionary<TKey, TValue> dictionary)
            {
                if (dictionary == null)
                    ThrowHelper.ThrowArgumentNullException(ExceptionArgument.dictionary);
                this.dictionary = dictionary;
            }

            public Enumerator GetEnumerator()
            {
                return new Enumerator(dictionary);
            }

            public void CopyTo(TKey[] array, int index)
            {
                if (array == null)
                    ThrowHelper.ThrowArgumentNullException(ExceptionArgument.array);
                if (index < 0 || index > array.Length)
                    ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.index, ExceptionResource.ArgumentOutOfRange_NeedNonNegNum);
                if (array.Length - index < dictionary.Count)
                    ThrowHelper.ThrowArgumentException(ExceptionResource.Arg_ArrayPlusOffTooSmall);
                int count = dictionary.count;
                Entry[] entries = dictionary.entries;
                for (int i = 0; i < count; i++)
                {
                    if (entries[i].hashCode >= 0)
                        array[index++] = entries[i].key;
                }
            }

            public int Count => dictionary.Count;

            bool ICollection<TKey>.IsReadOnly => true;

            void ICollection<TKey>.Add(TKey item)
            {
                ThrowHelper.ThrowNotSupportedException(ExceptionResource.NotSupported_KeyCollectionSet);
            }

            void ICollection<TKey>.Clear()
            {
                ThrowHelper.ThrowNotSupportedException(ExceptionResource.NotSupported_KeyCollectionSet);
            }

            bool ICollection<TKey>.Contains(TKey item)
            {
                return dictionary.ContainsKey(item);
            }

            bool ICollection<TKey>.Remove(TKey item)
            {
                ThrowHelper.ThrowNotSupportedException(ExceptionResource.NotSupported_KeyCollectionSet);
                return false;
            }

            IEnumerator<TKey> IEnumerable<TKey>.GetEnumerator()
            {
                return new Enumerator(dictionary);
            }

            IEnumerator IEnumerable.GetEnumerator()
            {
                return new Enumerator(dictionary);
            }

            void ICollection.CopyTo(Array array, int index)
            {
                if (array == null)
                    ThrowHelper.ThrowArgumentNullException(ExceptionArgument.array);
                if (array.Rank != 1)
                    ThrowHelper.ThrowArgumentException(ExceptionResource.Arg_RankMultiDimNotSupported);
                if (array.GetLowerBound(0) != 0)
                    ThrowHelper.ThrowArgumentException(ExceptionResource.Arg_NonZeroLowerBound);
                if (index < 0 || index > array.Length)
                    ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.index, ExceptionResource.ArgumentOutOfRange_NeedNonNegNum);
                if (array.Length - index < dictionary.Count)
                    ThrowHelper.ThrowArgumentException(ExceptionResource.Arg_ArrayPlusOffTooSmall);
                TKey[] array2 = array as TKey[];
                if (array2 != null)
                {
                    CopyTo(array2, index);
                    return;
                }
                object[] array3 = array as object[];
                if (array3 == null)
                    ThrowHelper.ThrowArgumentException(ExceptionResource.Argument_InvalidArrayType);
                int count = dictionary.count;
                Entry[] entries = dictionary.entries;
                try
                {
                    for (int i = 0; i < count; i++)
                    {
                        if (entries[i].hashCode >= 0)
                            array3[index++] = entries[i].key;
                    }
                }
                catch (ArrayTypeMismatchException)
                {
                    ThrowHelper.ThrowArgumentException(ExceptionResource.Argument_InvalidArrayType);
                }
            }

            bool ICollection.IsSynchronized => false;

            object ICollection.SyncRoot => ((ICollection)dictionary).SyncRoot;

            [Serializable]
            public struct Enumerator : IEnumerator<TKey>, IDisposable, IEnumerator
            {
                private readonly MyDictionary<TKey, TValue> dictionary;
                private int index;
                private TKey currentKey;

                internal Enumerator(MyDictionary<TKey, TValue> dictionary)
                {
                    this.dictionary = dictionary;
                    index = 0;
                    currentKey = default;
                }

                public void Dispose()
                {
                }

                public bool MoveNext()
                {
                    while (index < dictionary.count)
                    {
                        if (dictionary.entries[index].hashCode >= 0)
                        {
                            currentKey = dictionary.entries[index].key;
                            index++;
                            return true;
                        }
                        index++;
                    }
                    index = dictionary.count + 1;
                    currentKey = default;
                    return false;
                }

                public TKey Current => currentKey;

                object IEnumerator.Current => currentKey;

                void IEnumerator.Reset()
                {
                    index = 0;
                    currentKey = default;
                }
            }
        }

        [DebuggerTypeProxy(typeof(Mscorlib_DictionaryValueCollectionDebugView<,>))]
        [DebuggerDisplay("Count = {Count}")]
        [Serializable]
        public sealed class ValueCollection : ICollection<TValue>, IEnumerable<TValue>, IEnumerable, ICollection, IReadOnlyCollection<TValue>
        {
            private readonly MyDictionary<TKey, TValue> dictionary;

            public ValueCollection(MyDictionary<TKey, TValue> dictionary)
            {
                if (dictionary == null)
                    ThrowHelper.ThrowArgumentNullException(ExceptionArgument.dictionary);
                this.dictionary = dictionary;
            }

            public Enumerator GetEnumerator()
            {
                return new Enumerator(dictionary);
            }

            public void CopyTo(TValue[] array, int index)
            {
                if (array == null)
                    ThrowHelper.ThrowArgumentNullException(ExceptionArgument.array);
                if (index < 0 || index > array.Length)
                    ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.index, ExceptionResource.ArgumentOutOfRange_NeedNonNegNum);
                if (array.Length - index < dictionary.Count)
                    ThrowHelper.ThrowArgumentException(ExceptionResource.Arg_ArrayPlusOffTooSmall);
                int count = dictionary.count;
                Entry[] entries = dictionary.entries;
                for (int i = 0; i < count; i++)
                {
                    if (entries[i].hashCode >= 0)
                        array[index++] = entries[i].value;
                }
            }

            public int Count => dictionary.Count;

            bool ICollection<TValue>.IsReadOnly => true;

            void ICollection<TValue>.Add(TValue item)
            {
                ThrowHelper.ThrowNotSupportedException(ExceptionResource.NotSupported_ValueCollectionSet);
            }

            bool ICollection<TValue>.Remove(TValue item)
            {
                ThrowHelper.ThrowNotSupportedException(ExceptionResource.NotSupported_ValueCollectionSet);
                return false;
            }

            void ICollection<TValue>.Clear()
            {
                ThrowHelper.ThrowNotSupportedException(ExceptionResource.NotSupported_ValueCollectionSet);
            }

            bool ICollection<TValue>.Contains(TValue item)
            {
                return dictionary.ContainsValue(item);
            }

            IEnumerator<TValue> IEnumerable<TValue>.GetEnumerator()
            {
                return new Enumerator(dictionary);
            }

            IEnumerator IEnumerable.GetEnumerator()
            {
                return new Enumerator(dictionary);
            }

            void ICollection.CopyTo(Array array, int index)
            {
                if (array == null)
                    ThrowHelper.ThrowArgumentNullException(ExceptionArgument.array);
                if (array.Rank != 1)
                    ThrowHelper.ThrowArgumentException(ExceptionResource.Arg_RankMultiDimNotSupported);
                if (array.GetLowerBound(0) != 0)
                    ThrowHelper.ThrowArgumentException(ExceptionResource.Arg_NonZeroLowerBound);
                if (index < 0 || index > array.Length)
                    ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.index, ExceptionResource.ArgumentOutOfRange_NeedNonNegNum);
                if (array.Length - index < dictionary.Count)
                    ThrowHelper.ThrowArgumentException(ExceptionResource.Arg_ArrayPlusOffTooSmall);
                TValue[] array2 = array as TValue[];
                if (array2 != null)
                {
                    CopyTo(array2, index);
                    return;
                }
                object[] array3 = array as object[];
                if (array3 == null)
                    ThrowHelper.ThrowArgumentException(ExceptionResource.Argument_InvalidArrayType);
                int count = dictionary.count;
                Entry[] entries = dictionary.entries;
                try
                {
                    for (int i = 0; i < count; i++)
                    {
                        if (entries[i].hashCode >= 0)
                            array3[index++] = entries[i].value;
                    }
                }
                catch (ArrayTypeMismatchException)
                {
                    ThrowHelper.ThrowArgumentException(ExceptionResource.Argument_InvalidArrayType);
                }
            }

            bool ICollection.IsSynchronized => false;
            object ICollection.SyncRoot => ((ICollection)dictionary).SyncRoot;

            [Serializable]
            public struct Enumerator : IEnumerator<TValue>, IDisposable, IEnumerator
            {
                private readonly MyDictionary<TKey, TValue> dictionary;
                private int index;
                private TValue currentValue;

                internal Enumerator(MyDictionary<TKey, TValue> dictionary)
                {
                    this.dictionary = dictionary;
                    index = 0;
                    currentValue = default;
                }

                public void Dispose()
                {
                }

                public bool MoveNext()
                {
                    while (index < dictionary.count)
                    {
                        var entrie = dictionary.entries[index];
                        if (entrie.hashCode >= 0)
                        {
                            currentValue = entrie.value;
                            index++;
                            return true;
                        }
                        index++;
                    }
                    index = dictionary.count + 1;
                    currentValue = default;
                    return false;
                }

                public TValue Current => currentValue;

                object IEnumerator.Current => currentValue;

                void IEnumerator.Reset()
                {
                    index = 0;
                    currentValue = default;
                }
            }
        }
    }
}